// $Id: shm.c 45 2012-07-17 06:33:28Z alan.watson.f $

#define _POSIX_C_SOURCE 200112L

#include <string.h>

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "oaxaca-config.h"
#include "oaxaca.h"

oaxaca_shm_t * oaxaca_shm = NULL;

static size_t
roundup(size_t n, size_t m)
{
  if (n % m == 0)
    return n;
  else
    return (((n - 1) / m) + 1) * m;
}

static void *
shm_alloc(const char *name, size_t n)
{
  if (n == 0)
    return NULL;

  n = roundup(n, sysconf(_SC_PAGE_SIZE));
  
  int fd = shm_open(name, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
  if (fd == -1)
    return NULL;
  if (ftruncate(fd, n) == -1) {
    close(fd);
    return NULL;
  }
  void *p = mmap(NULL, n, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (p == MAP_FAILED) {
    close(fd);
    return NULL;
  }
  close(fd);
  return p;
}

const char *
oaxaca_shm_initialize(void)
{
  if (oaxaca_shm == NULL) {
    oaxaca_shm = (oaxaca_shm_t *) shm_alloc("/oaxaca", sizeof(*oaxaca_shm));
    if (oaxaca_shm == NULL)
      return "unable to allocate the shared memory.";
  }
  return NULL;
}
